﻿namespace WFBot.Workflow
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Activities;
    using System;
    using WFBot.Framework.Services;
    using Microsoft.Practices.Unity;
    using WFBot.Framework.Infrastructure;
    
    public class WorkflowService : IWorkflowService
    {
        private readonly Dictionary<string, WorkflowApplication> _applications;
        private readonly List<Message> _messages;
        private readonly List<string> _bookmarks;
        private readonly IBotService _botService;
        private readonly IUnityContainer _container;

        public WorkflowService(IBotService botService)
        {
            _applications = new Dictionary<string, WorkflowApplication>();
            _messages = new List<Message>();
            _bookmarks = new List<string>();
            _botService = botService;
            _container = new UnityContainer();
            IoC.Register(_container);
        }

        public void Run<TActivity>(string applicationName) where TActivity : class, new()
        {
            var activity = new TActivity() as Activity;

            var parameters = new Dictionary<string, object> { { "Channel", applicationName } };
            var workflowApplication = new WorkflowApplication(activity, parameters);
            workflowApplication.Extensions.Add(this);
            workflowApplication.Extensions.Add(_botService);
            workflowApplication.Extensions.Add(_container);

            _applications.Add(applicationName, workflowApplication);

            workflowApplication.Completed = (e) => {
                var pair = _applications.First(kvp => kvp.Value.Id == e.InstanceId);
                _applications.Remove(pair.Key);
            };
            workflowApplication.Run();
        }

        public void Resume(string applicationName, object value)
        {
            _applications[applicationName].ResumeBookmark(applicationName, value);
        }

        public void Push(Message message)
        {
            if (message.Origin == MessageOrigin.Server)
            {
                _messages.Add(message);
                return;
            }

            var channel = message.Channel;
            if (message.Type == MessageType.Response && _bookmarks.Contains(message.Channel))
            {
                Resume(channel, message);
                _bookmarks.Remove(channel);
            }
        }

        public List<Message> Pull(string channel)
        {
            var messages = _messages.Where(m => m.Channel == channel).ToList();
            _messages.RemoveAll(m => m.Channel == channel);
            return messages;
        }

        public void Bookmark(string channel)
        {
            _bookmarks.Add(channel);
        }
    }
}